import pygame
import json
import math
import random
from typing import List, Dict, Tuple
import boss

# 初始化pygame
pygame.init()

# 屏幕设置
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Boss Battle Visualization")

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
PURPLE = (128, 0, 128)
ORANGE = (255, 165, 0)
GRAY = (128, 128, 128)
DARK_GRAY = (64, 64, 64)
LIGHT_BLUE = (173, 216, 230)
GOLD = (255, 215, 0)

# 字体设置 - 支持中文
try:
    # 尝试使用系统中文字体
    font_large = pygame.font.SysFont("microsoftyaheimicrosoftyaheiui", 48)
    font_medium = pygame.font.SysFont("microsoftyaheimicrosoftyaheiui", 36)
    font_small = pygame.font.SysFont("microsoftyaheimicrosoftyaheiui", 24)
except:
    try:
        # 备选：使用其他中文字体
        font_large = pygame.font.SysFont("simhei", 48)
        font_medium = pygame.font.SysFont("simhei", 36)
        font_small = pygame.font.SysFont("simhei", 24)
    except:
        # 最后备选：使用默认字体
        font_large = pygame.font.Font(None, 48)
        font_medium = pygame.font.Font(None, 36)
        font_small = pygame.font.Font(None, 24)
        print("Warning: Chinese font not available, using default font")

class Particle:
    """粒子特效类"""
    def __init__(self, x, y, color, velocity, life_time):
        self.x = x
        self.y = y
        self.color = color
        self.velocity = velocity
        self.life_time = life_time
        self.max_life = life_time
        
    def update(self):
        self.x += self.velocity[0]
        self.y += self.velocity[1]
        self.life_time -= 1
        
    def draw(self, screen):
        if self.life_time > 0:
            alpha = int(255 * (self.life_time / self.max_life))
            color = (*self.color, alpha)
            pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), 3)

class SkillEffect:
    """技能特效类"""
    def __init__(self, start_pos, end_pos, skill_type, damage):
        self.start_pos = start_pos
        self.end_pos = end_pos
        self.skill_type = skill_type
        self.damage = damage
        self.progress = 0.0
        self.particles = []
        self.finished = False
        
    def update(self):
        if not self.finished:
            self.progress += 0.05
            
            # 计算当前位置
            current_x = self.start_pos[0] + (self.end_pos[0] - self.start_pos[0]) * self.progress
            current_y = self.start_pos[1] + (self.end_pos[1] - self.start_pos[1]) * self.progress
            
            # 根据技能类型添加粒子
            if self.skill_type == 0:  # 技能0：火球
                for _ in range(3):
                    vel = (random.uniform(-2, 2), random.uniform(-2, 2))
                    self.particles.append(Particle(current_x, current_y, RED, vel, 20))
            elif self.skill_type == 1:  # 技能1：闪电
                for _ in range(2):
                    vel = (random.uniform(-3, 3), random.uniform(-3, 3))
                    self.particles.append(Particle(current_x, current_y, YELLOW, vel, 15))
            elif self.skill_type == 2:  # 技能2：冰块
                for _ in range(2):
                    vel = (random.uniform(-1, 1), random.uniform(-1, 1))
                    self.particles.append(Particle(current_x, current_y, LIGHT_BLUE, vel, 25))
            
            if self.progress >= 1.0:
                self.finished = True
                # 击中特效
                for _ in range(20):
                    vel = (random.uniform(-5, 5), random.uniform(-5, 5))
                    color = [RED, YELLOW, ORANGE][self.skill_type % 3]
                    self.particles.append(Particle(self.end_pos[0], self.end_pos[1], color, vel, 30))
        
        # 更新粒子
        self.particles = [p for p in self.particles if p.life_time > 0]
        for particle in self.particles:
            particle.update()
    
    def draw(self, screen):
        # 绘制技能轨迹
        if not self.finished:
            current_x = self.start_pos[0] + (self.end_pos[0] - self.start_pos[0]) * self.progress
            current_y = self.start_pos[1] + (self.end_pos[1] - self.start_pos[1]) * self.progress
            
            # 技能图标
            colors = [RED, YELLOW, LIGHT_BLUE]
            pygame.draw.circle(screen, colors[self.skill_type % 3], (int(current_x), int(current_y)), 10)
        
        # 绘制粒子
        for particle in self.particles:
            particle.draw(screen)

class BossVisualization:
    def __init__(self, data: Dict):
        self.data = data
        print(data)
        self.bosses = data["B"][:]
        self.original_bosses = data["B"][:]
        self.skills = data["PlayerSkills"]
        self.current_boss = 0
        self.turn = 0
        self.cooldowns = [0] * len(self.skills)
        
        # 可视化状态
        self.effects = []
        self.game_state = "playing"  # playing, victory, game_over
        self.auto_play = False
        self.auto_actions = []
        self.auto_action_index = 0
        self.auto_delay = 0
        
        # 位置设置
        self.player_pos = (150, 400)
        self.boss_positions = [
            (800, 200), (1000, 200),
            (800, 400), (1000, 400)
        ]
        
        # 计算最优解
        result = boss.boss_battle_optimization(data)
        self.optimal_actions = result["actions"]
        self.optimal_turns = result["min_turns"]
        
    def get_current_boss_pos(self):
        if self.current_boss < len(self.boss_positions):
            return self.boss_positions[self.current_boss]
        return (900, 300)
    
    def use_skill(self, skill_idx: int):
        """使用技能"""
        if self.game_state != "playing":
            return False
        
        if self.cooldowns[skill_idx] > 0:
            return False
        
        # 创建技能特效
        effect = SkillEffect(self.player_pos, self.get_current_boss_pos(), skill_idx, self.skills[skill_idx][0])
        self.effects.append(effect)
        
        # 应用技能效果
        damage, cooldown_time = self.skills[skill_idx]
        self.bosses[self.current_boss] -= damage
        
        # 添加受击闪烁特效
        self.boss_hit_flash = 20  # 闪烁20帧
        
        # 更新冷却
        self.cooldowns = [max(0, cd - 1) for cd in self.cooldowns]
        self.cooldowns[skill_idx] = cooldown_time
        self.turn += 1
        
        # 检查boss是否被击败，但延迟切换boss
        if self.bosses[self.current_boss] <= 0:
            # 标记boss死亡，但要在下一次攻击时才切换
            if not hasattr(self, 'boss_death_pending'):
                self.boss_death_pending = True
        
        # 如果有待处理的boss死亡，现在切换
        if hasattr(self, 'boss_death_pending') and self.boss_death_pending:
            # 如果当前boss已死且不是刚死的（即上一轮就死了）
            if self.bosses[self.current_boss] <= 0:
                delattr(self, 'boss_death_pending')
                self.current_boss += 1
                if self.current_boss >= len(self.bosses):
                    self.game_state = "victory"
        
        return True
    
    def start_auto_play(self):
        """开始自动播放最优解"""
        self.auto_play = True
        self.auto_actions = self.optimal_actions[:]
        self.auto_action_index = 0
        self.auto_delay = 0
        
        # 重置游戏状态
        self.bosses = self.original_bosses[:]
        self.current_boss = 0
        self.turn = 0
        self.cooldowns = [0] * len(self.skills)
        self.game_state = "playing"
        self.effects = []
    
    def update(self):
        """更新游戏状态"""
        # 更新特效
        self.effects = [effect for effect in self.effects if not (effect.finished and not effect.particles)]
        for effect in self.effects:
            effect.update()
        
        # 自动播放逻辑
        if self.auto_play and self.game_state == "playing":
            self.auto_delay += 1
            if self.auto_delay >= 60:  # 1秒延迟
                if self.auto_action_index < len(self.auto_actions):
                    skill_idx = self.auto_actions[self.auto_action_index]
                    if self.use_skill(skill_idx):
                        self.auto_action_index += 1
                        self.auto_delay = 0
                else:
                    self.auto_play = False
    
    def draw_boss(self, screen, boss_idx: int):
        """绘制BOSS"""
        if boss_idx >= len(self.bosses):
            return
        
        pos = self.boss_positions[boss_idx] if boss_idx < len(self.boss_positions) else (900, 300)
        
        # BOSS外观状态判断
        if self.bosses[boss_idx] <= 0:
            # 已死亡BOSS - 灰色
            color = DARK_GRAY
        elif boss_idx == self.current_boss:
            # 当前激活的BOSS - 红色，可能有受击闪烁效果
            if hasattr(self, 'boss_hit_flash') and self.boss_hit_flash > 0:
                color = WHITE if self.boss_hit_flash % 10 < 5 else RED
                self.boss_hit_flash -= 1
            else:
                color = RED
        elif boss_idx < self.current_boss:
            # 已经击败的BOSS - 灰色
            color = DARK_GRAY
        else:
            # 未到达的BOSS - 彩色（根据索引用不同颜色）
            colors = [ORANGE, PURPLE, BLUE, GREEN]
            color = colors[boss_idx % len(colors)]
        
        # 绘制BOSS主体
        pygame.draw.circle(screen, color, pos, 50)
        pygame.draw.circle(screen, BLACK, pos, 50, 3)
        
        # BOSS编号
        boss_text = font_medium.render(f"BOSS{boss_idx+1}", True, WHITE)
        text_rect = boss_text.get_rect(center=(pos[0], pos[1] - 20))
        screen.blit(boss_text, text_rect)
        
        # 血量条（只显示活着的boss）
        if self.bosses[boss_idx] > 0:
            bar_width = 80
            bar_height = 10
            bar_x = pos[0] - bar_width // 2
            bar_y = pos[1] + 60
            
            # 血量条背景
            pygame.draw.rect(screen, DARK_GRAY, (bar_x, bar_y, bar_width, bar_height))
            
            # 血量条前景
            hp_ratio = self.bosses[boss_idx] / self.original_bosses[boss_idx]
            hp_width = int(bar_width * hp_ratio)
            health_color = GREEN if hp_ratio > 0.5 else YELLOW if hp_ratio > 0.2 else RED
            pygame.draw.rect(screen, health_color, (bar_x, bar_y, hp_width, bar_height))
            
            # 血量文字
            hp_text = font_small.render(f"{self.bosses[boss_idx]}/{self.original_bosses[boss_idx]}", True, WHITE)
            hp_rect = hp_text.get_rect(center=(pos[0], bar_y + bar_height + 15))
            screen.blit(hp_text, hp_rect)
    
    def draw_player(self, screen):
        """绘制玩家"""
        # 玩家主体
        pygame.draw.circle(screen, BLUE, self.player_pos, 30)
        pygame.draw.circle(screen, WHITE, self.player_pos, 30, 3)
        
        # 玩家标签
        player_text = font_medium.render("Player", True, WHITE)
        text_rect = player_text.get_rect(center=(self.player_pos[0], self.player_pos[1] - 50))
        screen.blit(player_text, text_rect)
    
    def draw_skills(self, screen):
        """绘制技能界面"""
        skill_area_y = SCREEN_HEIGHT - 150
        skill_width = 180
        skill_height = 100
        
        for i, (damage, cooldown_time) in enumerate(self.skills):
            x = 50 + i * (skill_width + 20)
            y = skill_area_y
            
            # 技能按钮背景
            if self.cooldowns[i] > 0:
                color = DARK_GRAY
                border_color = GRAY
            else:
                color = [PURPLE, ORANGE, LIGHT_BLUE][i % 3]
                border_color = WHITE
            
            pygame.draw.rect(screen, color, (x, y, skill_width, skill_height))
            pygame.draw.rect(screen, border_color, (x, y, skill_width, skill_height), 3)
            
            # 技能信息
            skill_text = font_medium.render(f"Skill {i}", True, WHITE)
            damage_text = font_small.render(f"Damage: {damage}", True, WHITE)
            cooldown_text = font_small.render(f"Cooldown: {cooldown_time}", True, WHITE)
            
            screen.blit(skill_text, (x + 10, y + 10))
            screen.blit(damage_text, (x + 10, y + 40))
            screen.blit(cooldown_text, (x + 10, y + 65))
            
            # 冷却时间显示
            if self.cooldowns[i] > 0:
                cd_text = font_large.render(str(self.cooldowns[i]), True, RED)
                cd_rect = cd_text.get_rect(center=(x + skill_width//2, y + skill_height//2))
                screen.blit(cd_text, cd_rect)
    
    def draw_ui(self, screen):
        """绘制UI信息"""
        # 回合数
        turn_text = font_large.render(f"Turn: {self.turn}", True, WHITE)
        screen.blit(turn_text, (20, 20))
        
        # 最优解信息
        optimal_text = font_medium.render(f"Optimal: {self.optimal_turns} turns", True, GOLD)
        screen.blit(optimal_text, (20, 70))
        
        # 当前BOSS提示
        if self.current_boss < len(self.bosses):
            boss_text = font_medium.render(f"Current Target: BOSS {self.current_boss}", True, WHITE)
            screen.blit(boss_text, (20, 110))
        
        # 按键提示
        if not self.auto_play:
            help_text = [
                "Controls:",
                "1,2,3 - Use Skills",
                "SPACE - Auto Play (Optimal)",
                "R - Reset Game"
            ]
            for i, text in enumerate(help_text):
                color = YELLOW if i == 0 else WHITE
                help_surface = font_small.render(text, True, color)
                screen.blit(help_surface, (SCREEN_WIDTH - 200, 20 + i * 25))
    
    def draw_victory(self, screen):
        """绘制胜利画面"""
        # 半透明覆盖
        overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
        overlay.set_alpha(180)
        overlay.fill(BLACK)
        screen.blit(overlay, (0, 0))
        
        # 胜利文字
        victory_text = font_large.render("VICTORY!", True, GOLD)
        victory_rect = victory_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 - 50))
        screen.blit(victory_text, victory_rect)
        
        # 统计信息
        stats_text = [
            f"Time: {self.turn} turns",
            f"Optimal: {self.optimal_turns} turns",
            f"Efficiency: {self.optimal_turns}/{self.turn} = {self.optimal_turns/max(self.turn,1):.2%}"
        ]
        
        for i, text in enumerate(stats_text):
            color = GREEN if "Efficiency" not in text else (GREEN if self.turn <= self.optimal_turns else YELLOW)
            stats_surface = font_medium.render(text, True, color)
            stats_rect = stats_surface.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + i * 40))
            screen.blit(stats_surface, stats_rect)
        
        # 重新开始提示
        restart_text = font_small.render("Press R to Restart", True, WHITE)
        restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2 + 150))
        screen.blit(restart_text, restart_rect)
    
    def draw(self, screen):
        """绘制所有内容"""
        screen.fill(BLACK)
        
        # 绘制背景
        pygame.draw.rect(screen, DARK_GRAY, (0, SCREEN_HEIGHT - 170, SCREEN_WIDTH, 170))
        
        # 绘制游戏元素
        self.draw_player(screen)
        
        for i in range(len(self.original_bosses)):
            self.draw_boss(screen, i)
        
        # 绘制特效
        for effect in self.effects:
            effect.draw(screen)
        
        # 绘制UI
        self.draw_skills(screen)
        self.draw_ui(screen)
        
        # 绘制胜利画面
        if self.game_state == "victory":
            self.draw_victory(screen)
    
    def handle_event(self, event):
        """处理事件"""
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_1:
                self.use_skill(0)
            elif event.key == pygame.K_2 and len(self.skills) > 1:
                self.use_skill(1)
            elif event.key == pygame.K_3 and len(self.skills) > 2:
                self.use_skill(2)
            elif event.key == pygame.K_SPACE:
                self.start_auto_play()
            elif event.key == pygame.K_r:
                # 重置游戏
                self.bosses = self.original_bosses[:]
                self.current_boss = 0
                self.turn = 0
                self.cooldowns = [0] * len(self.skills)
                self.game_state = "playing"
                self.effects = []
                self.auto_play = False

def main():
    """主函数"""
    # 加载数据
    json_path = "../算法课设/样例/BOSS战样例/boss_case_9.json"
    with open(json_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    # 创建可视化实例
    game = BossVisualization(data)
    
    # 游戏循环
    clock = pygame.time.Clock()
    running = True
    
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            else:
                game.handle_event(event)
        
        # 更新游戏状态
        game.update()
        
        # 绘制
        game.draw(screen)
        pygame.display.flip()
        
        # 控制帧率
        clock.tick(60)
    
    pygame.quit()

if __name__ == "__main__":
    main() 